/*
 * Copyright (C) 2016 Nishant Srivastava
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package github.nisrulz.easydeviceinfo.base;

import ohos.app.Context;
import ohos.batterymanager.BatteryInfo;
import ohos.event.commonevent.CommonEventData;
import ohos.event.commonevent.CommonEventManager;
import ohos.event.commonevent.CommonEventSubscribeInfo;
import ohos.event.commonevent.CommonEventSubscriber;
import ohos.event.commonevent.CommonEventSupport;
import ohos.event.commonevent.MatchingSkills;
import ohos.hiviewdfx.HiLog;
import ohos.rpc.RemoteException;

import java.util.Optional;

import github.nisrulz.easydeviceinfo.common.EasyDeviceInfo;

/**
 * EasyBattery Mod Class
 *
 * @since 2021-04-25
 */
@BatteryHealth
public class EasyBatteryMod {
    private final Context context;
    private BatteryInfo batteryInfo;
    CommonEventData batteryCommonEventData;
    private MyCommonEventSubscriber subscriber;
    private static final int defaultStatus = -1;
    private static final int defaultPercentage = 0;

    /**
     * Instantiates a new Easy battery mod.
     *
     * @param context the context
     */

    public EasyBatteryMod(final Context context) {
        this.context = context;
    }

    /**
     * Gets battery percentage.
     *
     * @return the battery percentage
     */
    public final int getBatteryPercentage() {
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        int percentage = batteryInfo.isPresent() ? batteryInfo.get().getCapacity() : defaultPercentage;
        return percentage;
    }

    private Optional<BatteryInfo> getBatteryStatusIntent() {
        if (batteryInfo == null) {
            batteryInfo = new BatteryInfo();
        }
        return Optional.ofNullable(batteryInfo);
    }

    /**
     * Is device charging boolean.
     *
     * @return is battery charging boolean
     */
    public final boolean isDeviceCharging() {
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        int status = batteryInfo.isPresent() ? batteryInfo.get().getChargingStatus().ordinal() : defaultStatus;
        return status == BatteryInfo.BatteryChargeState.ENABLE.ordinal()
            || status == BatteryInfo.BatteryChargeState.FULL.ordinal();
    }

    /**
     * Gets battery health.
     *
     * @return the battery health
     */
    @BatteryHealth
    public final int getBatteryHealth() {
        int health = BatteryHealth.HAVING_ISSUES;
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        if (batteryInfo.isPresent()) {
            health = batteryInfo.get().getHealthStatus().ordinal();
            if (health == BatteryInfo.BatteryHealthState.GOOD.ordinal()) {
                health = BatteryHealth.GOOD;
            } else {
                health = BatteryHealth.HAVING_ISSUES;
            }
        }
        return health;
    }

    /**
     * Gets battery technology.
     *
     * @return the battery technology
     */
    public final String getBatteryTechnology() {
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        return CheckValidityUtil.checkValidData(
            batteryInfo.isPresent() ? batteryInfo.get().getTechnology() : "");
    }

    /**
     * Gets battery temprature.
     *
     * @return the battery temprature
     */
    public final float getBatteryTemperature() {
        float temp = 0.0f;
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        if (batteryInfo.isPresent()) {
            temp = (float) (batteryInfo.get().getBatteryTemperature() / 10.0);
        }
        return temp;
    }

    /**
     * Gets battery voltage.
     *
     * @return the battery voltage
     */
    public final int getBatteryVoltage() {
        int volt = 0;
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent();
        if (batteryInfo.isPresent()) {
            volt = batteryInfo.get().getVoltage();
        }
        return volt;
    }

    /**
     * Gets charging source.
     *
     * @return the charging source
     */
    @ChargingVia
    public final int getChargingSource() {
        Optional<BatteryInfo> batteryInfo = getBatteryStatusIntent().isPresent() ? getBatteryStatusIntent() : null;
        BatteryInfo.BatteryPluggedType chargePlug = batteryInfo.isPresent() ? batteryInfo.get().getPluggedType() : null;
        switch (chargePlug) {
            case AC:
                return ChargingVia.AC;
            case USB:
                return ChargingVia.USB;
            case WIRELESS:
                return ChargingVia.WIRELESS;
            default:
                return ChargingVia.UNKNOWN_SOURCE;
        }
    }


    /**
     * 是否存在电池
     *
     * @param batteryCallback 回调方法
     */
    public void isBatteryPresent(BatteryCallback batteryCallback) {
        MatchingSkills matchingSkills = new MatchingSkills();
        matchingSkills.addEvent(CommonEventSupport.COMMON_EVENT_BATTERY_CHANGED); // 电池事件
        CommonEventSubscribeInfo subscribeInfo = new CommonEventSubscribeInfo(matchingSkills);
        subscriber = new MyCommonEventSubscriber(subscribeInfo, batteryCallback);
        try {
            CommonEventManager.subscribeCommonEvent(subscriber);
        } catch (RemoteException e) {
            HiLog.error(EasyDeviceInfo.LABEL, "Exception occurred during subscribeCommonEvent invocation.");
        }
    }

    /**
     * 取消订阅
     */
    private void unsubscribeCommonEvent() {
        if (subscriber != null) {
            try {
                CommonEventManager.unsubscribeCommonEvent(subscriber);
            } catch (RemoteException e) {
                e.getMessage();
            }
        }
    }

    /**
     * 订阅电池信息
     *
     * @since 2021-04-25
     */
    private class MyCommonEventSubscriber extends CommonEventSubscriber {
        BatteryCallback batteryCallback;

        MyCommonEventSubscriber(CommonEventSubscribeInfo info, BatteryCallback batteryCallback) {
            super(info);
            this.batteryCallback = batteryCallback;
        }

        @Override
        public void onReceiveEvent(CommonEventData commonEventData) {
            batteryCommonEventData = commonEventData;
            boolean isBattery = batteryCommonEventData.getIntent().getBooleanParam(BatteryInfo.OHOS_BATTERY_PRESENT, false);
            if (batteryCallback != null) {
                batteryCallback.onSuccess(isBattery);
                unsubscribeCommonEvent();
            }
        }
    }

    /**
     * The interface Ad identifier callback.
     *
     * @since 2021-04-25
     */
    public interface BatteryCallback {
        /**
         * On success.
         * the ad identifier
         *
         * @param isBatteryPresent Is battery present
         */
        void onSuccess(boolean isBatteryPresent);
    }
}